package org.apache.derby.shared.common.sanity;

import java.util.Hashtable;

/**
 * @author ex_chenzy59
 * @since 2025/3/13
 *
 */
public class SanityManager {
    public static final boolean ASSERT = SanityState.ASSERT; // code should use DEBUG
    public static final boolean DEBUG = SanityState.DEBUG;
    static private Hashtable<String,Boolean> DebugFlags = new Hashtable<String,Boolean>();
    static private boolean AllDebugOn = false;
    static private boolean AllDebugOff = false;
    static private java.io.PrintWriter debugStream = new java.io.PrintWriter(System.err);
    public static final String DEBUGDEBUG = "DumpSanityDebug";
    public static void THROWASSERT(String msgIfFail) {
        // XXX (nat) Hmm, should we check ASSERT here?  The caller is
        // not expecting this function to return, whether assertions
        // are compiled in or not.
        THROWASSERT(msgIfFail, null);
    }
    public static void THROWASSERT(String msg, Throwable t) {
        var af = new AssertFailure("ASSERT FAILED " + msg, t);
        if (DEBUG&&DEBUG_ON("AssertFailureTrace")) {
            showTrace(af);
        }
        if (t != null) {
            showTrace(t);
        }
        throw af;
    }
    static private void showTrace(AssertFailure af) {
        af.printStackTrace();
        var assertStream = GET_DEBUG_STREAM();

        assertStream.println("Assertion trace:");
        af.printStackTrace(assertStream);
        assertStream.flush();
    }
    static public void showTrace(Throwable t) {
        var assertStream = GET_DEBUG_STREAM();
        assertStream.println("Exception trace: ");
        t.printStackTrace(assertStream);
    }
    static public java.io.PrintWriter GET_DEBUG_STREAM() {
        return debugStream;
    }
    public static final boolean DEBUG_ON(String flag) {
        if (!DEBUG){
            return false;
        }
        if (AllDebugOn){
            return true;
        }
        if (AllDebugOff){
            return false;
        }
        var flagValue = DebugFlags.get(flag);
        if (! DEBUGDEBUG.equals(flag)) {
            if (DEBUG_ON(DEBUGDEBUG)) {
                DEBUG_PRINT(DEBUGDEBUG, STR."DEBUG_ON: Debug flag \{flag} = \{flagValue}");
            }
        }
        return flagValue != null && flagValue;
    }
    static public void DEBUG_PRINT(String flag, String message) {
        var debugStream = GET_DEBUG_STREAM();

        debugStream.println("DEBUG "+flag+" OUTPUT: " + message);
        debugStream.flush();
    }
    public static final void ASSERT(boolean mustBeTrue, String msgIfFail) {
        if (DEBUG)
            if (! mustBeTrue) {
                if (DEBUG) {
                    AssertFailure af = new AssertFailure("ASSERT FAILED " + msgIfFail);
                    if (DEBUG_ON("AssertFailureTrace")) {
                        showTrace(af);
                    }
                    throw af;
                }
                else
                    throw new AssertFailure("ASSERT FAILED " + msgIfFail);
            }
    }
}
